#ifndef VENDOR_ECARX_CONNECTIVITY_V1_0_CONNECTIVITY_H
#define VENDOR_ECARX_CONNECTIVITY_V1_0_CONNECTIVITY_H

#include <vendor/ecarx/xma/connectivity/1.0/IConnectivity.h>
#include <vendor/ecarx/xma/connectivity/1.0/IConnectivityCallback.h>
#include <vendor/ecarx/xma/connectivity/1.0/types.h>
#include "WorkerThread.h"
#include <ipcp/ipcp.h>
#include <unistd.h>
#include <string>

#include <android/hardware/automotive/vehicle/2.0/IVehicleCallback.h>
#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
#include <android/hardware/automotive/vehicle/2.0/types.h>
#include <vendor/ecarx/xma/automotive/vehicle/2.0/types.h>

using ::android::hardware::automotive::vehicle::V2_0::VehicleProperty;
using ::android::hardware::automotive::vehicle::V2_0::VehiclePropValue;
//using vendor::ecarx::xma::automotive::vehicle::V1_0::VendorVehicleProperty;

typedef android::hardware::automotive::vehicle::V2_0::StatusCode Automotive_StatusCode;

namespace vendor
{
namespace ecarx
{
namespace xma
{
namespace connectivity
{
namespace V1_0
{
namespace implementation
{

using std::lock_guard;
using std::mutex;
using std::chrono::milliseconds;
using std::chrono_literals::operator""ms;
using std::string;
using ::android::sp;
using ::android::wp;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_death_recipient;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_array;
using namespace ::android::hardware::automotive::vehicle::V2_0;

#define ASN_HEADER_LENGTH_OFFSET 8

// Only for Local Test --- S
// #define LOCAL_IP "127.0.0.1"
// #define PEER_IP "127.0.0.1"

// #define SERVICE_LOCAL_PORT            (7777)
// #define SERVICE_PEER_PORT             (5555)
// Only for Local Test --- E

#define LOCAL_IP "198.18.34.15"
#define PEER_IP "198.18.32.17"

// Define Service Port
#define SERVICE_LOCAL_PORT            (50177)
#define SERVICE_PEER_PORT             (50177)

// Define Service ID
#define SERVICE_ID_CONNECTIVITY       0xB1

#define SERVICE_VLAN_ID               (2)
#define SERVICE_VLAN_PCP              (0)

// Define Operation Type
#define OP_TYPE_REQUEST               0x00
#define OP_TYPE_SET_REQUEST           0x02
#define OP_TYPE_RESPONSE              0x04
#define OP_TYPE_NOTIFICATION          0x05
#define OP_TYPE_NOTIFICATION_CYCLIC   0x06
#define OP_TYPE_ERROR                 0xe0

enum {
    OP_ID_OpESIMConnectionStatus = 0x0001,
    OP_ID_OpWLANMode = 0x0011,
    OP_ID_OpWLANAPSETTING = 0x0012,
    OP_ID_OpWLANAPConnDevList = 0x0013,
    OP_ID_OpWLANSTAConnect = 0x0014,
    OP_ID_OpWLANSTAStatus = 0x0015,
    OP_ID_OpWLANSTARememberedNetwks = 0x0016,
    OP_ID_OpWLANSTAForgetRememberedNetwk = 0x0017,
    OP_ID_OpWLANSTAScan = 0x0019,
    OP_ID_OpWLANLOGSETTING = 0x001A,
    OP_ID_SyncTCAMinformation = 0x001B,
    OP_ID_OpWLANModeReq = 0x001C,
    OP_ID_OpWLANLogSettingReq = 0x001D,
    OP_ID_OpWLANSTADisCon = 0x0020,
    OP_ID_TestConnectionStatus = 0x0021,
    OP_ID_NetworkConnectionStatus = 0x0022,
    OP_ID_5GModeReq = 0x0024,
    OP_ID_Set5GMode = 0x0025
};


struct Connectivity : public IConnectivity {
    public:
        Connectivity();
        ~Connectivity();

        virtual void onFirstRef();

        Return<StatusCode> queryCurrentWifiMode() override;
        Return<StatusCode> setWifiEnabled(bool enabled) override;
        Return<StatusCode> setWifiAPEnabled(bool enabled) override;
        Return<StatusCode> startScan() override;
        Return<StatusCode> connectNetwork(const WifiConfigurationHAL& config) override;
        Return<StatusCode> disconnectNetwork(const hidl_string& ssid) override;
        Return<StatusCode> queryRememberedNetworks() override;
        Return<StatusCode> forgetNetwork(const SavedNetwork& network) override;
        Return<StatusCode> queryCurrentWifiStatus() override;

        Return<StatusCode> setWifiApConfiguration(const WifiApConfigurationHAL& ap_config) override;
        Return<StatusCode> queryCurrentApConfiguration() override;
        Return<StatusCode> queryWifiApConnectedDevs() override;

        Return<StatusCode> setTcamWlanLogSettings(bool enabled) override;
        Return<StatusCode> queryTcamSyncInformation() override;

        Return<StatusCode> registerIConnectivityCallback(const sp<IConnectivityCallback>& callback) override;
        Return<StatusCode> unregisterIConnectivityCallback(const sp<IConnectivityCallback>& callback) override;

        Return<StatusCode> queryCurrentTcamLogSettings() override;
        Return<StatusCode> testCurrentConnectionStatus() override;

        Return<StatusCode> set5GMode(bool enabled) override;
        Return<StatusCode> req5GMode() override;

        static sp<Connectivity> getConnectivity(void *cookie);
        sp<IConnectivityCallback> getCallback();

        void handleHidlDeath();
        void setup_wifi_ipcp();
        std::thread mIpcpThread;

        void setupVehicle();
        bool setValue(VehiclePropValue setProp);
        void setIncompatibleIpcpDtc();

    private:

        class DeathRecipient : public hidl_death_recipient {
            public:
                DeathRecipient(sp<Connectivity> connectivity) : mConnnectivity(connectivity) {}
                ~DeathRecipient() = default;
                void serviceDied(uint64_t cookie /*cookie*/,
                                         const wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
                    ALOGD("function: %s, service %lu", __func__, cookie);
                    mConnnectivity->handleHidlDeath();
                }

            private:
                sp<Connectivity> mConnnectivity;
        };

        mutex mMut;
        sp<IConnectivityCallback> mCallback;
        sp<DeathRecipient> mCallbackDeathRecipient;
        WorkerThread mThread;
        sp<IVehicle> mVehicle = nullptr;
};

} // implementation
} // V1_0
} // connectivity
} // xma
} // ecarx
} // vendor

#endif // VENDOR_ECARX_CONNECTIVITY_V1_0_CONNECTIVITY_H
